<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="YeT45" id="YeT45"><span data-lake-id="ue8881e95" id="ue8881e95">典型回答</span></h1>
  <p data-lake-id="u1d8f2309" id="u1d8f2309"><span data-lake-id="ud3c8cd4c" id="ud3c8cd4c">​</span><br></p>
  <p data-lake-id="ue39d1ed3" id="ue39d1ed3"><span data-lake-id="u37638324" id="u37638324">常见的垃圾回收器如下：</span></p>
  <ol list="uc579b04b">
   <li fid="u038d0206" data-lake-id="u98cadf9c" id="u98cadf9c"><span data-lake-id="ufcb73146" id="ufcb73146"> 串行垃圾回收器（Serial Garbage Collector） 如：</span><span data-lake-id="u140a7e74" id="u140a7e74" class="lake-fontsize-12" style="color: rgb(85, 85, 85)">Serial GC， Serial Old</span></li>
   <li fid="u038d0206" data-lake-id="u831102d2" id="u831102d2"><span data-lake-id="ue71d64e9" id="ue71d64e9"> 并行垃圾回收器（Parallel Garbage Collector） 如：</span><span data-lake-id="u0d8751f6" id="u0d8751f6" class="lake-fontsize-12" style="color: rgb(85, 85, 85)">Parallel Scavenge，Parallel Old，ParNew</span></li>
   <li fid="u038d0206" data-lake-id="u766eac0e" id="u766eac0e"><span data-lake-id="ud4891e5c" id="ud4891e5c"> 并发标记扫描垃圾回收器（CMS Garbage Collector） </span></li>
   <li fid="u038d0206" data-lake-id="u7b4b79f0" id="u7b4b79f0"><span data-lake-id="u3b01ff4f" id="u3b01ff4f"> G1垃圾回收器（G1 Garbage Collector，JDK 7中推出，JDK 9中设置为默认） </span></li>
   <li fid="u038d0206" data-lake-id="uc8a5b702" id="uc8a5b702"><span data-lake-id="u02ca19cc" id="u02ca19cc">ZGC垃圾回收器（</span><span data-lake-id="ud4356fb7" id="ud4356fb7" style="color: rgb(51, 51, 51); background-color: rgb(253, 253, 253)">The Z Garbage Collector，JDK 11 推出）</span></li>
  </ol>
  <p data-lake-id="u01bc9672" id="u01bc9672"><br></p>
  <p data-lake-id="ue97b4576" id="ue97b4576"><strong><span data-lake-id="u4463d7ab" id="u4463d7ab">新生代收集器有Serial、ParNew、Parallel Scavenge；</span></strong></p>
  <p data-lake-id="u646e8294" id="u646e8294"><strong><span data-lake-id="u098aadb8" id="u098aadb8">老年代收集器有Serial Old、Parallel Old、CMS。</span></strong></p>
  <p data-lake-id="ub17e6d00" id="ub17e6d00"><strong><span data-lake-id="ufed3c06a" id="ufed3c06a">整堆收集器有G1、ZGC</span></strong></p>
  <p data-lake-id="udef1474b" id="udef1474b"><span data-lake-id="u8a4e3bdb" id="u8a4e3bdb">​</span><br></p>
  <p data-lake-id="ua27606bb" id="ua27606bb"><img src="https://cdn.nlark.com/yuque/0/2022/png/5378072/1671864805509-c14c2f9a-33b2-4750-ac63-574578f9cc38.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_64%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <h1 data-lake-id="opt9h" id="opt9h"><span data-lake-id="u8eb5a032" id="u8eb5a032">扩展知识</span></h1>
  <h2 data-lake-id="pKWve" id="pKWve"><span data-lake-id="u3ab1f998" id="u3ab1f998">串行垃圾收集器</span></h2>
  <h3 data-lake-id="Mecfy" id="Mecfy"><span data-lake-id="u00d99a1a" id="u00d99a1a" style="color: rgb(0, 0, 0)">Serial GC</span></h3>
  <p data-lake-id="u9c33c079" id="u9c33c079"><strong><span data-lake-id="u5c4d699f" id="u5c4d699f">Serial是单线程的串行垃圾回收器，主要采用</span></strong><code data-lake-id="u701a05f1" id="u701a05f1"><strong><span data-lake-id="ub0ae674b" id="ub0ae674b" style="color: #213BC0">标记-复制算法</span></strong></code><strong><span data-lake-id="ucd6a7fe2" id="ucd6a7fe2">进行垃圾回收。</span></strong></p>
  <p data-lake-id="ua66adcff" id="ua66adcff"><strong><span data-lake-id="ucc5746e8" id="ucc5746e8">​</span></strong><br></p>
  <p data-lake-id="u03eff782" id="u03eff782"><span data-lake-id="uf457c4ca" id="uf457c4ca">单线程地好处就是减少上下文切换，减少系统资源的开销。但这种方式的缺点也很明显，在GC的过程中，必须暂停其他所有的工作线程，直至Serial收集器收集结束为止（Stop The World）。若GC不是频繁发生，这或许是一个不错的选择，否则将会影响程序的执行性能。 </span></p>
  <p data-lake-id="ue027308d" id="ue027308d"><span data-lake-id="ud7830d60" id="ud7830d60">​</span><br></p>
  <h3 data-lake-id="x2e0f" id="x2e0f"><span data-lake-id="ucf01290a" id="ucf01290a" style="color: rgb(51, 51, 51)">Serial Old</span></h3>
  <p data-lake-id="u0b0150ac" id="u0b0150ac"><span data-lake-id="uf34032ec" id="uf34032ec">​</span><br></p>
  <p data-lake-id="u4763a0e2" id="u4763a0e2"><strong><span data-lake-id="uf9b2cad8" id="uf9b2cad8">Serial Old是Serial的老年代版本，也是个单线程收集器，适用于老年代，使用的是</span></strong><code data-lake-id="uab70ddf5" id="uab70ddf5"><strong><span data-lake-id="u07bdec6d" id="u07bdec6d" style="color: #AE146E">标记-整理算法</span></strong></code><strong><span data-lake-id="ua6b808c0" id="ua6b808c0">。</span></strong></p>
  <p data-lake-id="u5a2f8a98" id="u5a2f8a98"><strong><span data-lake-id="uff72a1ee" id="uff72a1ee">​</span></strong><br></p>
  <p data-lake-id="ud90071ca" id="ud90071ca"><span data-lake-id="uec20a2cb" id="uec20a2cb">优缺点基本和Serial差不多，二者主要是回收算法不一样。</span></p>
  <p data-lake-id="uaf415230" id="uaf415230" style="text-align: left"><span data-lake-id="ufeb601ba" id="ufeb601ba" class="lake-fontsize-12" style="color: rgb(51, 51, 51)">​</span><br></p>
  <h2 data-lake-id="qCJPq" id="qCJPq"><span data-lake-id="uc3adc4c2" id="uc3adc4c2" style="color: rgb(51, 51, 51)">并行垃圾收集器</span></h2>
  <h3 data-lake-id="TVbRx" id="TVbRx"><span data-lake-id="u1b86c474" id="u1b86c474" style="color: rgb(33, 37, 41)">ParNew</span></h3>
  <p data-lake-id="u8271059e" id="u8271059e"><br></p>
  <p data-lake-id="uf1663108" id="uf1663108"><strong><span data-lake-id="u64e30d37" id="u64e30d37">ParNew其实就是Serial的多线程版本，在参数、回收算法上，和</span></strong><strong><span data-lake-id="u09aadd19" id="u09aadd19" style="color: rgb(0, 0, 0)">Serial是完全一样的，所以他也是采用</span></strong><code data-lake-id="u82857362" id="u82857362"><strong><span data-lake-id="u9bc3ed2d" id="u9bc3ed2d" style="color: #213BC0">标记-复制算法</span></strong></code><strong><span data-lake-id="u5d83cb51" id="u5d83cb51" style="color: rgb(0, 0, 0)">进行垃圾回收的。</span></strong></p>
  <p data-lake-id="u2a3fac4b" id="u2a3fac4b"><span data-lake-id="ua5355ce3" id="ua5355ce3">​</span><br></p>
  <p data-lake-id="udfc7ea3f" id="udfc7ea3f"><span data-lake-id="u99651b03" id="u99651b03">ParNew在垃圾回收的时候，同样会STW，但是因为它是多线程并行进行垃圾回收的，所以通常情况下时间会比Serial短一些。</span></p>
  <p data-lake-id="u199ef8f3" id="u199ef8f3"><br></p>
  <h3 data-lake-id="GqpqU" id="GqpqU"><span data-lake-id="u99ec44f2" id="u99ec44f2" style="color: rgb(85, 85, 85)">Parallel Scavenge</span></h3>
  <p data-lake-id="ua492e713" id="ua492e713"><span data-lake-id="uee3b7e42" id="uee3b7e42">​</span><br></p>
  <p data-lake-id="uce297ade" id="uce297ade"><strong><span data-lake-id="ud7adb592" id="ud7adb592">Parallel Scavenge 也是一个新生代的垃圾回收器，和ParNew一样，他也是多线程并发执行的，同样采用的也是</span></strong><code data-lake-id="u30c66f03" id="u30c66f03"><strong><span data-lake-id="u19e34671" id="u19e34671" style="color: #213BC0">标记-复制算法</span></strong></code><span data-lake-id="ud7736350" id="ud7736350">。与ParNew最大的不同是，Parallel Scavenge 关注的是垃圾回收的吞吐量（吞吐量=代码运行时间/(代码运行时间+垃圾收集时间)，以吞吐量优先。</span></p>
  <p data-lake-id="ua40b5652" id="ua40b5652"><span data-lake-id="u18e762d4" id="u18e762d4">​</span><br></p>
  <p data-lake-id="uf47f8d9f" id="uf47f8d9f"><span data-lake-id="u4526b013" id="u4526b013">因为Parallel Scavenge收集器的高吞吐量可以最高效率的利用CPU时间，尽快的完成程序的运算任务等，所以他主要适合在后台运算，比如一些定时任务的执行。</span></p>
  <p data-lake-id="ude9a4fd8" id="ude9a4fd8"><span data-lake-id="u965bf58f" id="u965bf58f">​</span><br></p>
  <h3 data-lake-id="cE6MP" id="cE6MP"><span data-lake-id="u6e27af83" id="u6e27af83">Parallel Old</span></h3>
  <p data-lake-id="u9c17d6d6" id="u9c17d6d6"><strong><span data-lake-id="uc50fa0f8" id="uc50fa0f8">Parallel 是 Parallel Scavenge的老年代版本，同样是一个关注吞吐量的并行垃圾收集器，他采用的是</span></strong><code data-lake-id="u2fb15591" id="u2fb15591"><strong><span data-lake-id="u8f153ed5" id="u8f153ed5" style="color: #AE146E">标记-整理算法</span></strong></code><strong><span data-lake-id="uc5bb1cae" id="uc5bb1cae">算法进行垃圾回收的。</span></strong></p>
  <p data-lake-id="u1d72a0b1" id="u1d72a0b1"><br></p>
  <h2 data-lake-id="OTRMw" id="OTRMw"><span data-lake-id="ub7442cc3" id="ub7442cc3">CMS</span></h2>
  <p data-lake-id="uc9a3630a" id="uc9a3630a"><br></p>
  <p data-lake-id="u91a877b6" id="u91a877b6"><span data-lake-id="u6aa19600" id="u6aa19600">CMS，Concurrent Mark Sweep，同样是老年代的收集器。他也是一个并发执行的垃圾收集器，他和Parallel最大的区别是他更加关注垃圾回收的停顿时间，通过他的名字Concurrent Mark Sweep就可以知道，他采用的是耗时更短的</span><code data-lake-id="uaf384bce" id="uaf384bce"><strong><span data-lake-id="u009123af" id="u009123af" style="color: #5C8D07">标记-清除算法</span></strong></code><span data-lake-id="uf801347e" id="uf801347e">。</span></p>
  <p data-lake-id="u979fa85f" id="u979fa85f"><br></p>
  <p data-lake-id="uaf8d98cf" id="uaf8d98cf"><span data-lake-id="u98fb150b" id="u98fb150b">CMS收集器的工作流程主要有下面4个步骤：</span></p>
  <p data-lake-id="uf7022738" id="uf7022738"><br></p>
  <ol list="uaa2b04bc">
   <li fid="uf67f7425" data-lake-id="uea11f3e3" id="uea11f3e3"><span data-lake-id="ud7084419" id="ud7084419">初始标记：独占CPU，仅标记GCroots能直接关联的对象（STW）</span></li>
   <li fid="uf67f7425" data-lake-id="u696ab809" id="u696ab809"><span data-lake-id="uf8e1bd63" id="uf8e1bd63">并发标记：可以和用户线程并发执行，标记所有可达对象</span></li>
   <li fid="uf67f7425" data-lake-id="u56775f38" id="u56775f38"><span data-lake-id="u48f60752" id="u48f60752">重新标记：独占CPU，对并发标记阶段用户线程运行产生的垃圾对象中产生变动的一部分对象进行标记修正(STW)</span></li>
   <li fid="uf67f7425" data-lake-id="u5c02feb9" id="u5c02feb9"><span data-lake-id="uced95fb9" id="uced95fb9">并发清理：可以和用户线程并发执行，清理垃圾</span></li>
  </ol>
  <p data-lake-id="u2f415609" id="u2f415609"><br></p>
  <p data-lake-id="ue3516daa" id="ue3516daa"><img src="https://cdn.nlark.com/yuque/0/2022/png/719664/1670157866341-bf6b1111-db74-46fa-914e-cf4e1a4621fa.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_16%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u9fc8abad" id="u9fc8abad"><br></p>
  <p data-lake-id="u65a5c1c1" id="u65a5c1c1"><strong><span data-lake-id="ua9bfb4f3" id="ua9bfb4f3">从上面的四个步骤中可以看出，CMS的过程中，只有初始标记和重新标记这两个步骤是STW的，所以，相比其他的收集器整个回收过程都STW来说，他导致的应用停顿时间更短。</span></strong></p>
  <p data-lake-id="u9a59abfa" id="u9a59abfa"><br></p>
  <p data-lake-id="u5c465cd3" id="u5c465cd3"><span data-lake-id="u574d5772" id="u574d5772">优点:</span></p>
  <ol list="u6e8e36bb">
   <li fid="u65fefe29" data-lake-id="uec979833" id="uec979833"><span data-lake-id="uc9658376" id="uc9658376">并发</span></li>
   <li fid="u65fefe29" data-lake-id="u30578791" id="u30578791"><span data-lake-id="u21d9f463" id="u21d9f463">低停顿</span></li>
  </ol>
  <p data-lake-id="u26ee70df" id="u26ee70df"><br></p>
  <p data-lake-id="u75de9bb1" id="u75de9bb1"><span data-lake-id="ufa5ede13" id="ufa5ede13">缺点：</span></p>
  <ol list="ue8e01efb">
   <li fid="u08d033a0" data-lake-id="ucfdf32f4" id="ucfdf32f4"><span data-lake-id="u87e18c9f" id="u87e18c9f">对CPU非常敏感：在并发阶段虽然不会导致用户线程停顿，但是会因为占用了一部分线程使应用程序变慢</span></li>
   <li fid="u08d033a0" data-lake-id="ue3950730" id="ue3950730"><span data-lake-id="u6d83f6e6" id="u6d83f6e6">无法处理浮动垃圾：在最后一步并发清理过程中，用户线程执行也会产生垃圾，但是这部分垃圾是在标记之后，所以只有等到下一次gc的时候清理掉，这部分垃圾叫浮动垃圾</span></li>
   <li fid="u08d033a0" data-lake-id="uc332e4b2" id="uc332e4b2"><span data-lake-id="u75ea253d" id="u75ea253d">CMS使用“标记-清理”法会产生大量的空间碎片，当碎片过多，将会给大对象空间的分配带来很大的麻烦，往往会出现老年代还有很大的空间但无法找到足够大的连续空间来分配当前对象，不得不提前触发一次FullGC，为了解决这个问题CMS提供了一个开关参数，用于在CMS顶不住，要进行FullGC时开启内存碎片的合并整理过程，但是内存整理的过程是无法并发的，空间碎片没有了但是停顿时间变长了</span></li>
  </ol>
  <p data-lake-id="uf1b39f47" id="uf1b39f47"><br></p>
  <h2 data-lake-id="DJSsO" id="DJSsO"><span data-lake-id="u43d9ec52" id="u43d9ec52">G1</span></h2>
  <p data-lake-id="u4ce9fb28" id="u4ce9fb28"><br></p>
  <p data-lake-id="ue81641d4" id="ue81641d4"><br></p>
  <h2 data-lake-id="Rr4Nz" id="Rr4Nz"><span data-lake-id="ud6ddd233" id="ud6ddd233">ZGC</span></h2>
  <p data-lake-id="ub6dd2c5f" id="ub6dd2c5f"><br></p>
 </body>
</html>